import json
import os
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, \
    QScrollArea, QMessageBox, QSpacerItem
from PyQt5.QtGui import QPixmap

from encrypt_all_files import process_directory, encrypt_file
from socketU import *
from PyQt5.QtCore import Qt



# 定义代码到中文名称的映射
CODE_TO_NAME = {
    "kLeftShoulderPitch": "左肩关节俯仰",
    "kLeftShoulderRoll": "左肩关节侧滚",
    "kLeftShoulderYaw": "左肩关节偏航",
    "kLeftElbow": "左肘关节",
    "kLeftWristRoll": "左手腕侧滚",
    "kLeftWristPitch": "左手腕俯仰",
    "kLeftWristYaw": "左手腕偏航",
    "kRightShoulderPitch": "右肩关节俯仰",
    "kRightShoulderRoll": "右肩关节侧滚",
    "kRightShoulderYaw": "右肩关节偏航",
    "kRightElbow": "右肘关节",
    "kRightWristRoll": "右手腕侧滚",
    "kRightWristPitch": "右手腕俯仰",
    "kRightWristYaw": "右手腕偏航",
    "kWaistYaw": "腰部偏航",
    "kWaistRoll": "腰部侧滚",
    "kWaistPitch": "腰部俯仰"
}

# 为每个条目添加 current 字段，初始值为 default

JOINT_DATA_WITH_DEFAULT = [
    {"code": "kLeftShoulderPitch", "name": CODE_TO_NAME["kLeftShoulderPitch"], "min": -3.0892, "default": 0.292139, "max": 2.6704, "current": 0.292139},
    {"code": "kLeftShoulderRoll", "name": CODE_TO_NAME["kLeftShoulderRoll"], "min": -1.5882, "default": 0.220713, "max": 2.2515, "current": 0.220713},
    {"code": "kLeftShoulderYaw", "name": CODE_TO_NAME["kLeftShoulderYaw"], "min": -2.618, "default": -0.00117445, "max": 2.618, "current": -0.00117445},
    {"code": "kLeftElbow", "name": CODE_TO_NAME["kLeftElbow"], "min": -1.0472, "default": 0.977721, "max": 2.0944, "current": 0.977721},
    {"code": "kLeftWristRoll", "name": CODE_TO_NAME["kLeftWristRoll"], "min": -1.9722, "default": 0.050933, "max": 1.9722, "current": 0.050933},
    {"code": "kLeftWristPitch", "name": CODE_TO_NAME["kLeftWristPitch"], "min": -1.6144, "default": 0.0229714, "max": 1.6144, "current": 0.0229714},
    {"code": "kLeftWristYaw", "name": CODE_TO_NAME["kLeftWristYaw"], "min": -1.6144, "default": -0.0037966, "max": 1.6144, "current": -0.0037966},
    {"code": "kRightShoulderPitch", "name": CODE_TO_NAME["kRightShoulderPitch"], "min": -3.0892, "default": 0.291504, "max": 2.6704, "current": 0.291504},
    {"code": "kRightShoulderRoll", "name": CODE_TO_NAME["kRightShoulderRoll"], "min": -2.2515, "default": -0.226418, "max": 1.5882, "current": -0.226418},
    {"code": "kRightShoulderYaw", "name": CODE_TO_NAME["kRightShoulderYaw"], "min": -2.618, "default": 0.00385892, "max": 2.618, "current": 0.00385892},
    {"code": "kRightElbow", "name": CODE_TO_NAME["kRightElbow"], "min": -1.0472, "default": 0.977841, "max": 2.0944, "current": 0.977841},
    {"code": "kRightWristRoll", "name": CODE_TO_NAME["kRightWristRoll"], "min": -1.9722, "default": -0.101027, "max": 1.9722, "current": -0.101027},
    {"code": "kRightWristPitch", "name": CODE_TO_NAME["kRightWristPitch"], "min": -1.6144, "default": -0.060039, "max": 1.6144, "current": -0.060039},
    {"code": "kRightWristYaw", "name": CODE_TO_NAME["kRightWristYaw"], "min": -1.6144, "default": 0.0171883, "max": 1.6144, "current": 0.0171883},
    {"code": "kWaistYaw", "name": CODE_TO_NAME["kWaistYaw"], "min": -2.618, "default": -0.00121866, "max": 2.618, "current": -0.00121866},
    {"code": "kWaistRoll", "name": CODE_TO_NAME["kWaistRoll"], "min": -0.52, "default": 0.0, "max": 0.52, "current": 0.0},
    {"code": "kWaistPitch", "name": CODE_TO_NAME["kWaistPitch"], "min": -0.52, "default": 0.0, "max": 0.52, "current": 0.0}
]


class MainWindow(QWidget):


    min_gesture_duration = 0.2

    default_step = 0.05
    debug_gesture_duration = 0.2
    min_action_duration = 1


    def __init__(self):
        super().__init__()
        self.socket_client = TCPClient("192.168.110.252", 8080)
        self.socket_client.connect()
        self.initUI()
        self.action_counter = 0  # 初始化动作计数器

        # key: 动作的索引， value: 动作的数据
        self.actions = dict()
        self.current_modify_action_idx = None

    def initUI(self):
        # 主布局，分为左右两部分
        main_layout = QHBoxLayout()
        main_layout.setSpacing(10)
        main_layout.setContentsMargins(10, 10, 10, 10)

        # 左侧部分，先预留 30% 空间
        left_widget = QWidget()
        left_layout = QVBoxLayout()
        left_widget.setLayout(left_layout)

        # 创建滚动区域
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)

        # 创建滚动区域内的部件
        scroll_content_widget = QWidget()
        self.scroll_content_layout = QVBoxLayout()
        scroll_content_widget.setLayout(self.scroll_content_layout)

        # 将滚动区域内的部件设置到滚动区域中
        scroll_area.setWidget(scroll_content_widget)

        # 将滚动区域添加到左侧布局，并设置拉伸因子使其占据剩余空间
        left_layout.addWidget(scroll_area, 1)

        # 添加动作名称输入框
        self.sequence_name_edit = QLineEdit()
        left_layout.addWidget(self.sequence_name_edit)

        # 添加一键导出按钮
        export_button = QPushButton('一键导出')
        export_button.clicked.connect(self.export_action)
        left_layout.addWidget(export_button)

        main_layout.addWidget(left_widget, 3)
        # 保存 left_layout 作为实例属性，方便后续访问
        self.left_layout = left_layout

        # 右侧部分，占 70% 空间，使用水平布局
        right_widget = QWidget()
        right_layout = QHBoxLayout()
        right_layout.setSpacing(10)
        right_layout.setContentsMargins(10, 10, 10, 10)

        # 分离左右关节和腰部数据
        left_joints = [data for data in JOINT_DATA_WITH_DEFAULT if 'Left' in data['code']]
        right_joints = [data for data in JOINT_DATA_WITH_DEFAULT if 'Right' in data['code']]
        waist_joints = [data for data in JOINT_DATA_WITH_DEFAULT if 'Waist' in data['code']]

        # 存储所有值标签，方便后续更新
        left_value_labels = []
        middle_value_labels = []
        right_value_labels = []
        self.value_labels = []

        # 左侧关节设置
        left_joint_widget = QWidget()
        left_joint_layout = QVBoxLayout()
        left_joint_layout.setSpacing(5)
        left_joint_layout.setContentsMargins(5, 5, 5, 5)
        for joint in left_joints:
            h_layout = QHBoxLayout()
            h_layout.setSpacing(5)
            name_label = QLabel(joint["name"])
            minus_btn = QPushButton('-')
            btn_size = 45
            minus_btn.setFixedSize(btn_size, btn_size)
            # 替换 QLabel 为 QLineEdit
            value_input = QLineEdit(f"{round(joint['current'], 5)}")
            value_input.setFixedWidth(100)  # 设置输入框宽度
            plus_btn = QPushButton('+')
            plus_btn.setFixedSize(btn_size, btn_size)

            minus_btn.clicked.connect(lambda _, input_field=value_input, min_val=joint['min'], max_val=joint['max'], step=-1 * MainWindow.default_step, idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.update_value(input_field, min_val, max_val, step, idx))
            plus_btn.clicked.connect(lambda _, input_field=value_input, min_val=joint['min'], max_val=joint['max'], step= MainWindow.default_step, idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.update_value(input_field, min_val, max_val, step, idx))

            # 连接输入框的编辑完成信号到更新值的函数
            value_input.editingFinished.connect(lambda input_field=value_input, min_val=joint['min'], max_val=joint['max'], idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.manual_update_value(input_field, min_val, max_val, idx))
            left_value_labels.append(value_input)


            h_layout.addWidget(name_label)
            h_layout.addWidget(minus_btn)
            h_layout.addWidget(value_input)
            h_layout.addWidget(plus_btn)
            left_joint_layout.addLayout(h_layout)
        left_joint_widget.setLayout(left_joint_layout)
        right_layout.addWidget(left_joint_widget)

        # 中间腰部和一键恢复设置区域
        middle_widget = QWidget()
        middle_layout = QVBoxLayout()
        middle_layout.setSpacing(5)

        sync_button = QPushButton('同步数据')
        sync_button.clicked.connect(self.get_position)
        restore_button = QPushButton('一键复位')
        restore_button.clicked.connect(self.restore_values)
        save_button = QPushButton('保存动作')
        save_button.clicked.connect(self.save_action)

        bg_image_path = "ic_g1.png"
        pixmap = QPixmap(bg_image_path)
        if not pixmap.isNull():
            image_label = QLabel()
            image_label.setPixmap(pixmap.scaled(image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
            image_label.setAlignment(Qt.AlignCenter)
            middle_layout.addWidget(image_label, alignment=Qt.AlignCenter)

        middle_layout.addStretch()

        # 腰部关节设置
        waist_joint_widget = QWidget()
        waist_joint_layout = QVBoxLayout()
        waist_joint_layout.setSpacing(5)
        waist_joint_layout.setContentsMargins(5, 5, 5, 5)
        for joint in waist_joints:
            h_layout = QHBoxLayout()
            h_layout.setSpacing(5)
            name_label = QLabel(joint["name"])
            minus_btn = QPushButton('-')
            minus_btn.setFixedSize(btn_size, btn_size)
            # 替换 QLabel 为 QLineEdit
            value_input = QLineEdit(f"{round(joint['current'], 5)}")
            value_input.setFixedWidth(100)  # 设置输入框宽度
            plus_btn = QPushButton('+')
            plus_btn.setFixedSize(btn_size, btn_size)

            minus_btn.clicked.connect(lambda _, input_field=value_input, min_val=joint['min'], max_val=joint['max'], step=-1 * MainWindow.default_step, idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.update_value(input_field, min_val, max_val, step, idx))
            plus_btn.clicked.connect(lambda _, input_field=value_input, min_val=joint['min'], max_val=joint['max'], step=MainWindow.default_step, idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.update_value(input_field, min_val, max_val, step, idx))

            # 连接输入框的编辑完成信号到更新值的函数
            value_input.editingFinished.connect(lambda input_field=value_input, min_val=joint['min'], max_val=joint['max'], idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.manual_update_value(input_field, min_val, max_val, idx))

            middle_value_labels.append(value_input)

            h_layout.addWidget(name_label)
            h_layout.addWidget(minus_btn)
            h_layout.addWidget(value_input)
            h_layout.addWidget(plus_btn)
            waist_joint_layout.addLayout(h_layout)
        waist_joint_widget.setLayout(waist_joint_layout)
        middle_layout.addWidget(waist_joint_widget)

        middle_widget.setLayout(middle_layout)
        right_layout.addWidget(middle_widget)

        # 右侧关节设置
        right_joint_widget = QWidget()
        right_joint_layout = QVBoxLayout()
        right_joint_layout.setSpacing(5)
        right_joint_layout.setContentsMargins(5, 5, 5, 5)
        for joint in right_joints:
            h_layout = QHBoxLayout()
            h_layout.setSpacing(5)
            name_label = QLabel(joint["name"])
            minus_btn = QPushButton('-')
            minus_btn.setFixedSize(btn_size, btn_size)
            # 替换 QLabel 为 QLineEdit
            value_input = QLineEdit(f"{round(joint['current'], 5)}")
            value_input.setFixedWidth(100)  # 设置输入框宽度
            plus_btn = QPushButton('+')
            plus_btn.setFixedSize(btn_size, btn_size)

            minus_btn.clicked.connect(lambda _, input_field=value_input, min_val=joint['min'], max_val=joint['max'], step=-1 * MainWindow.default_step, idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.update_value(input_field, min_val, max_val, step, idx))
            plus_btn.clicked.connect(lambda _, input_field=value_input, min_val=joint['min'], max_val=joint['max'], step=MainWindow.default_step, idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.update_value(input_field, min_val, max_val, step, idx))

            # 连接输入框的编辑完成信号到更新值的函数
            value_input.editingFinished.connect(lambda input_field=value_input, min_val=joint['min'], max_val=joint['max'], idx=JOINT_DATA_WITH_DEFAULT.index(joint): self.manual_update_value(input_field, min_val, max_val, idx))

            right_value_labels.append(value_input)

            h_layout.addWidget(name_label)
            h_layout.addWidget(minus_btn)
            h_layout.addWidget(value_input)
            h_layout.addWidget(plus_btn)
            right_joint_layout.addLayout(h_layout)
        right_joint_widget.setLayout(right_joint_layout)
        right_layout.addWidget(right_joint_widget)

        self.value_labels.extend(left_value_labels)
        self.value_labels.extend(right_value_labels)
        self.value_labels.extend(middle_value_labels)


        # 新增右侧控制列
        control_widget = QWidget()
        control_layout = QVBoxLayout()
        control_layout.setSpacing(5)

        # 进一步减小 control_widget 的固定宽度，你可以根据需要继续调整这个值
        control_widget.setFixedWidth(150) 

        # 动作时长设置，改为上下结构
        duration_widget = QWidget()
        duration_layout = QVBoxLayout()

        buttons_layout = QHBoxLayout()
        duration_label = QLabel('时长')
        duration_label.setAlignment(Qt.AlignCenter)  # 让标签居中显示

        # 缩小加减按钮的大小
        small_btn_size = 30
        minus_duration_btn = QPushButton('-')
        plus_duration_btn = QPushButton('+')
        minus_duration_btn.setFixedSize(small_btn_size, small_btn_size)
        plus_duration_btn.setFixedSize(small_btn_size, small_btn_size)

        minus_duration_btn.clicked.connect(self.decrease_duration)
        plus_duration_btn.clicked.connect(self.increase_duration)

        buttons_layout.addWidget(minus_duration_btn)
        buttons_layout.addWidget(duration_label)
        buttons_layout.addWidget(plus_duration_btn)

        duration_layout.addLayout(buttons_layout)

        self.duration_input = QLineEdit(f"{MainWindow.debug_gesture_duration}")
        self.duration_input.setFixedWidth(100)  # 设置输入框宽度
        duration_layout.addWidget(self.duration_input)
        duration_widget.setLayout(duration_layout)

        # 添加发送动作按钮
        send_action_button = QPushButton('发送动作')
        # 假设存在一个 send_action 方法来处理发送动作的逻辑
        send_action_button.clicked.connect(self.send_action)


        control_layout.addWidget(sync_button)
        control_layout.addWidget(restore_button)
        control_layout.addStretch(1)
        control_layout.addWidget(duration_widget)
        control_layout.addWidget(send_action_button)
        control_layout.addWidget(save_button)

        control_widget.setLayout(control_layout)
        right_layout.addWidget(control_widget)

        right_widget.setLayout(right_layout)
        main_layout.addWidget(right_widget, 7)

        self.setLayout(main_layout)
        self.setWindowTitle('关节设置界面')

        # 获取屏幕信息
        screen = QApplication.primaryScreen()
        screen_geometry = screen.geometry()
        screen_width = screen_geometry.width()
        screen_height = screen_geometry.height()
        # 设置窗口宽度为屏幕宽度，高度保持不变
        self.setGeometry(0, 300, screen_width, screen_height)
        self.show()

    def send_action(self):
        """ 发送动作的处理函数，可根据实际需求实现具体逻辑 """
        # 这里可以添加发送动作的具体代码，例如通过 socket 发送数据等
        current_duration = float(self.duration_input.text())
        if current_duration < MainWindow.min_gesture_duration:
            QMessageBox.warning(self, "错误", f"动作时长不能小于{MainWindow.min_gesture_duration}")
        else:
            self.send_command()
            pass

    def save_action(self):
        """ 保存动作的处理函数 """
        if self.current_modify_action_idx is not None:
            current_duration = float(self.duration_input.text())
            need_send_values = [round(item["current"], 5) for item in JOINT_DATA_WITH_DEFAULT]
            data = dict(type="MOVE", position=need_send_values, duration = current_duration)
            print(f"----update action: {self.current_modify_action_idx}, {data}")
            self.actions[self.current_modify_action_idx] = data

            target_widget = None
            print(f"-----count(): {self.scroll_content_layout.count()}")
            for idx in range(self.scroll_content_layout.count()):
                item = self.scroll_content_layout.itemAt(idx).widget()
                if item:
                    if item.objectName() and int(item.objectName()) == int(self.current_modify_action_idx):
                        target_widget = item

            if target_widget:
                duration_layout = target_widget.layout()
                duration_label = duration_layout.itemAt(1).widget()
                if duration_label:
                    duration_label.setText(str(current_duration))


            self.current_modify_action_idx = None
            QMessageBox.warning(self, "提示", f"更新成功！")

        else:
            action_name = f"动作{self.action_counter}"
            action_label = QLabel(action_name)

            # 获取当前动作时长
            current_duration = float(self.duration_input.text())
            duration_label = QLabel(str(current_duration))
            duration_label.setFixedWidth(50)  # 设置时长标签宽度

            # 创建删除按钮
            delete_button = QPushButton('删除')
            delete_button.setObjectName(f"{self.action_counter}")
            delete_button.clicked.connect(lambda _, layout_index=int(delete_button.objectName()) : self.delete_action(layout_index))

            # 创建修改按钮
            modify_button = QPushButton('修改')
            modify_button.setObjectName(f"{self.action_counter}")
            modify_button.clicked.connect(lambda _, layout_index=int(modify_button.objectName())  : self.modify_action(layout_index))

            h_layout = QHBoxLayout()
            h_layout.setSpacing(10)  # 设置布局内控件间距
            h_layout.addWidget(action_label)
            h_layout.addWidget(duration_label)
            h_layout.addWidget(delete_button)
            h_layout.addWidget(modify_button)

            # 创建一个容器部件，并设置背景色、固定高度和文字颜色
            container_widget = QWidget()
            # 设置固定高度为 40 像素，你可以根据需要调整
            container_widget.setFixedHeight(70)
            # 设置背景色为灰色，文字颜色为白色，确保对比度
            container_widget.setStyleSheet("background-color: #666666; color: white; margin: 5px; padding: 5px;")
            container_widget.setLayout(h_layout)
            container_widget.setObjectName(f"{self.action_counter}")
            # 移除之前添加的用于避免占满父容器高度的 stretch
            if self.scroll_content_layout.count() > 1 and isinstance(self.scroll_content_layout.itemAt(self.scroll_content_layout.count() - 1), QSpacerItem):
                self.scroll_content_layout.removeItem(self.scroll_content_layout.itemAt(self.scroll_content_layout.count() - 1))

            # 确保布局底部有一个 stretch 来避免设备布局占满父容器高度
            if self.scroll_content_layout.count() == 1 or not isinstance(self.scroll_content_layout.itemAt(self.scroll_content_layout.count() - 1), QSpacerItem):
                self.scroll_content_layout.addStretch()

            self.scroll_content_layout.insertWidget(self.action_counter, container_widget)  # 在顶部插入新部件


            # 缓存当前关节数据 "type": "MOVE",
            need_send_values = [round(item["current"], 5)  for item in JOINT_DATA_WITH_DEFAULT]
            data = dict(type="MOVE", positions=need_send_values, duration=current_duration)
            print(f"----add action: {data}")
            self.actions[self.action_counter] = data


            self.action_counter += 1  # 计数器加 1


    def delete_action(self, layout_index):
        """ 删除动作的处理函数 """
        print(f"-----layout_index: {layout_index}")
        # 弹出确认提示框
        reply = QMessageBox.question(self, '确认删除', '确定要删除这个动作吗？', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            target_widget = None
            print(f"-----count(): {self.scroll_content_layout.count()}")
            for idx in range(self.scroll_content_layout.count()):
                item = self.scroll_content_layout.itemAt(idx).widget()
                if item:
                    if item.objectName() and int(item.objectName()) == layout_index:
                        target_widget = item
            # 从界面上移除对应的控件
            if target_widget:
                target_widget.deleteLater()
                self.scroll_content_layout.removeWidget(target_widget)

            # 从缓存中删除相应的数据项
            if layout_index in self.actions:
                del self.actions[layout_index]
            print(f"-----self.actions: {self.actions}")


    def modify_action(self, layout_index):
        """ 修改动作的处理函数 """
        if layout_index in self.actions:
            action = self.actions[layout_index]
            self.current_modify_action_idx = layout_index

            positions = action['position']
            print(positions)
            for (index , item) in enumerate(JOINT_DATA_WITH_DEFAULT):
                item['current'] = positions[index]
                # 更新对应的标签文本
                if index < len(self.value_labels):
                    self.value_labels[index].setText(f"{round(positions[index], 5)}")


    def export_action(self):
        """ 导出动作的处理函数 """
        # 例如，可以将当前关节数据保存到文件
        file_name = "joint_data.json"
        encrypt_file_name = "joint_data.bin"
        file_path = os.path.join(os.path.dirname(__file__), file_name)
        encrypt_file_path = os.path.join(os.path.dirname(__file__), encrypt_file_name)
        actions = list(self.actions.values())

        sequence_name = self.sequence_name_edit.text()
        if sequence_name != "":
            export_data = dict()
            export_sequence = dict()
            export_sequence[sequence_name] = actions
            export_data["sequences"] = export_sequence
            print(f"----export_data:{export_data}")

            with open('joint_data.json', 'w') as f:
                json.dump(export_data, f)
            self.encrypt_data(file_path, encrypt_file_path)
        else:
            QMessageBox.warning(self, "错误", f"名称不能为空")

    def encrypt_data(self, src_path, target_path):
        """ 加密数据的处理函数 """
        try:
            success = encrypt_file(src_path ,target_path )
            if success:
                QMessageBox.warning(self, "提示", f"导出成功，数据存储在:{target_path}")
        except Exception as e:
            QMessageBox.warning(self, "提示", f"导出失败，数据存储在:{e}")
            pass


    def decrease_duration(self):
        try:
            current_duration = float(self.duration_input.text())
            new_duration = current_duration - 0.1
            if new_duration >= MainWindow.min_gesture_duration:
                new_duration = round(new_duration, 2)
                self.duration_input.setText(str(new_duration))
                MainWindow.debug_gesture_duration = new_duration
            else:
                QMessageBox.warning(self, "错误", f"动作时长不能小于{MainWindow.min_gesture_duration}")
        except Exception as e:
            print(f"-----error: {e}")


    def increase_duration(self):
        try:
            current_duration = float(self.duration_input.text())
            new_duration = current_duration + 0.1
            new_duration = round(new_duration, 2)
            self.duration_input.setText(str(new_duration))
            MainWindow.debug_gesture_duration = new_duration
        except ValueError:
            QMessageBox.warning(self, "错误", "输入值不是有效的数字")


    def recv_callback(self, data):
        """ 接收数据回调函数 """
        print(f"Received data: {data}")

    def get_position(self):
        """ 获取当前关节位置 """
        if self.socket_client.client_socket:
            self.socket_client.send_data("get position")
            res = json.loads(self.socket_client.receive_data())
            print(f"----res: {res}")

            for (index , item) in enumerate(JOINT_DATA_WITH_DEFAULT):
                item['current'] = res[index]
                # 更新对应的标签文本
                if index < len(self.value_labels):
                    self.value_labels[index].setText(f"{round(res[index], 5)}")

    def update_value(self, input_field, min_val, max_val, step, idx):
        try:
            current_value = float(input_field.text())
            new_value = current_value + step
            if min_val <= new_value <= max_val:
                JOINT_DATA_WITH_DEFAULT[idx]['current'] = new_value
                input_field.setText(f"{round(new_value, 5)}")
                self.send_command()

        except ValueError:
            print("输入值不是有效的数字")

    def manual_update_value(self, input_field, min_val, max_val, idx):
        try:
            new_value = float(input_field.text())
            if min_val <= new_value <= max_val:
                JOINT_DATA_WITH_DEFAULT[idx]['current'] = new_value
                # self.send_command()
            else:
                # 恢复原来的值
                input_field.setText(f"{round(JOINT_DATA_WITH_DEFAULT[idx]['current'], 5)}")
        except ValueError:
            # 输入值不是有效的数字，恢复原来的值
            input_field.setText(f"{round(JOINT_DATA_WITH_DEFAULT[idx]['current'], 5)}")
            print("输入值不是有效的数字")

    def send_command(self):
        """ 发送命令到服务器 """
        if self.socket_client.client_socket:
            current_duration = float(self.duration_input.text())
            need_send_values = [item["current"] for item in JOINT_DATA_WITH_DEFAULT]
            data = dict(type="MOVE", position=need_send_values, duration=round(current_duration , 5))
            print(f"----send data: {data}")
            self.socket_client.send_data(f"set position = {need_send_values}")

            res = json.loads(self.socket_client.receive_data())
            print(f"----res: {res}")

            for (index, item) in enumerate(JOINT_DATA_WITH_DEFAULT):
                item['current'] = res[index]
                if index < len(self.value_labels):
                    self.value_labels[index].setText(f"{round(res[index], 5)}")

    def restore_values(self):
        if self.socket_client.client_socket:
            # command = dict(command = "restore")
            # self.socket_client.send_data(json.dumps(command))
            self.socket_client.send_data("restore")

    def print_all_data(self):
        all_values = []
        for item in JOINT_DATA_WITH_DEFAULT:
            command = f"set {item['code']} = {item['current']}"
            all_values.append(command)
        print(f"-----all_values: {all_values}")



if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec_())




